<template>
  <q-card>
    <q-card-section>
      <div class="text-h6">货物分类</div>
    </q-card-section>

    <q-separator />

    <q-card-actions>
      <div class="fit row no-wrap">
        <div>
          <q-btn :disable="!canAdd" color="blue-8" label="新增" @click="add()" />
          <q-btn :disable="!canEdit" color="secondary" label="修改" @click="edit()" />
          <q-btn :disable="!canDelete" color="grey" label="删除" @click="destroy()" />
        </div>
        <q-space />
        <div style="max-width: 170px;">
          <q-input ref="filter" filled dense v-model="filter" label="查找...">
            <template v-slot:append>
              <q-icon v-if="filter !== ''" name="clear" class="cursor-pointer" @click="resetFilter" />
            </template>
          </q-input>
        </div>
      </div>
    </q-card-actions>

    <q-separator />

    <q-scroll-area style="height: calc(100vh - 122px);">
      <q-card-section>
        <q-tree
          ref="catalog"
          :nodes="tree"
          node-key="id"
          v-model:selected="selectedId"
          selected-color="blue-8"
          default-expand-all
          :filter="filter"
        >
          <template v-slot:default-header="prop">
            <div>{{ prop.node.label }}</div>
            <q-space />
            <q-btn-group outline v-if="prop.node.parent_id >= 0 && canEdit">
              <q-btn outline :color="sortBtnColor(prop.node.levels)" size="xs" dense icon="keyboard_arrow_up" @click.stop="changeSort(prop.node, 'f')">
                <q-tooltip>上移</q-tooltip>
              </q-btn>
              <q-btn outline :color="sortBtnColor(prop.node.levels)" size="xs" dense icon="keyboard_arrow_down" @click.stop="changeSort(prop.node, 'b')">
                <q-tooltip>下移</q-tooltip>
              </q-btn>
            </q-btn-group>
          </template>
          <template v-slot:body-rule="prop">
            <div v-if="prop.node.code_rule">
              <div v-if="prop.node.code_rule.prefix_type === 'fixed'">货物编码规则：编码前缀+分类编码+流水号</div>
              <div v-if="prop.node.code_rule.prefix_type === 'dynamic'">货物编码规则：货物名称的拼音首字母+流水号</div>
            </div>
          </template>
        </q-tree>
      </q-card-section>
    </q-scroll-area>
  </q-card>

  <dialogForm ref="dialogForm" :config="dialogConfig" />
</template>

<script>
import { defineComponent } from 'vue';
import { mapState, mapActions } from 'pinia';
import { useStore } from 'stores/store';
import dialogForm from 'components/DialogInputForm.vue';

export default defineComponent({
  name: 'materialCatalog',
  emits: ['selected'],
  inject: ['confirmBox'],
  components: {
    dialogForm
  },
  data () {
    return {
      tree: [],
      selectedId: null,
      selectedNode: null,
      dialogConfig: {
        title: '货物分类',
        fields: {
          id: { value: '', default: -1 },
          parent_id: { value: '', default: -1 },
          catalog_code: { type: 'input', label: '分类编码', value: '', default: '', readonly: false },
          catalog_name: { type: 'input', label: '分类名称', value: '', default: '', readonly: false },
          sell: {
            type: 'toggle',
            label: '是否上架',
            value: 1,
            trueValue: 1,
            trueLabel: '是',
            falseValue: 0,
            falseLabel: '否',
            default: 1,
            hidden: true
          },
          customize: {
            type: 'toggle',
            label: '自定义货物编码规则',
            value: false,
            default: false,
            hint: ''
          },
          prefix_type: {
            type: 'radio',
            label: '编码前缀类型',
            value: '',
            default: 'fixed',
            options: [
              { value: 'fixed', label: '固定值' },
              { value: 'dynamic', label: '拼音首字母' }
            ],
            group: 'code_rule',
            hidden: true
          },
          prefix: { type: 'input', label: '编码前缀', value: '', default: 'MDY', group: 'code_rule', hidden: true },
          rule: {
            type: 'checkbox',
            label: '包含分类编码',
            value: [],
            default: ['1', '2', '3', '4'],
            options: [
              { value: '1', label: '一级分类' },
              { value: '2', label: '二级分类' },
              { value: '3', label: '三级分类' },
              { value: '4', label: '四级分类' }
            ],
            group: 'code_rule',
            hidden: true
          },
          digits: {
            type: 'input',
            label: '流水号长度',
            value: '',
            default: 4,
            group: 'code_rule',
            hidden: true
          }
        }
      },
      filter: ''
    }
  },
  mounted () {
  },
  methods: {
    // locateId - 选中的id, expendId - 展开的id，例：{ c1: xx, c2: xxx }
    refresh (locateId, expendIds) {
      this.$axios.get('/c2/tenant/material/catalogList').then(({ data }) => {
        this.tree = data.catalog;
        this.$nextTick(() => {
          this.$refs.catalog.setExpanded(this.tree[0].id, true);
          if (locateId) {
            this.selectedId = locateId;
            this.selectedNode = this.$refs.catalog.getNodeByKey(locateId);
          } else {
            if (!this.selectedId) {
              this.selectedId = this.tree[0].id;
            } else {
              this.selectedNode = this.$refs.catalog.getNodeByKey(this.selectedId);
            }
          }
          if (expendIds) {
            for (const id in expendIds) {
              expendIds[id] && this.$refs.catalog.setExpanded(expendIds[id], true);
            }
          }
        });
      });
    },
    maxCode () {
      const node = this.selectedNode || this.tree[0];
      let code = '01';
      if (node.children && node.children.length > 0) {
        code = Number(node.children[node.children.length - 1].catalog_code) + 1;
        code = String(code).length == 1 ? '0' + code : String(code);
      }
      return code;
    },
    add () { // 新增
      this.dialogConfig.title = `新增${this.selectedNode ? this.selectedNode.label : ''}的子级分类`;
      for (const [key, item] of Object.entries(this.dialogConfig.fields)) {
        item.value = item.default;
      }
      this.dialogConfig.fields.parent_id.value = this.selectedNode ? this.selectedNode.id : this.tree[0].id;
      this.dialogConfig.fields.catalog_code.value = this.maxCode();

      this.dialogConfig.fields.catalog_code.readonly = false;
      this.dialogConfig.fields.catalog_name.readonly = false;
      this.dialogConfig.fields.sell.hidden = this.selectedNode.levels !== 1;
      this.resetRuleCfg();

      this.$refs.dialogForm.show().then(formData => {
        if (formData) {
          if (formData.customize) {
            const code_rule = {};
            for (const [key, item] of Object.entries(this.dialogConfig.fields)) {
              if (item.group === 'code_rule') {
                code_rule[key] = formData[key];
              }
            }
            formData.code_rule = code_rule;
          } else {
            formData.code_rule = null;
          }
          delete formData.id;

          this.$axios.post('/c2/tenant/material/catalogCreate', { formData }).then(({ data }) => {
            if (data.result === 'fail') {
              this.$q.notify({
                message: data.message || '保存失败',
                color: 'negative',
                icon: 'error',
                position: 'top',
                timeout: 5000
              });
            } else {
              this.$q.notify({
                message: '保存成功',
                color: 'secondary',
                icon: 'done',
                position: 'top',
                timeout: 2000
              });
              this.refresh(this.selectedId, { c: this.selectedId });
              // this.selectedId && this.$refs.catalog.setExpanded(this.selectedId, true);
            }
          });
        }
      });
    },
    edit () {
      this.dialogConfig.title = `修改${this.selectedNode.label}`;

      this.dialogConfig.fields.catalog_code.readonly = this.selectedNode.parent_id === -1;
      this.dialogConfig.fields.catalog_name.readonly = this.selectedNode.parent_id === -1;
      this.dialogConfig.fields.sell.hidden = this.selectedNode.levels !== 2;

      // 赋值
      for (const [key, item] of Object.entries(this.dialogConfig.fields)) {
        if (this.selectedNode[key] !== null && this.selectedNode[key] !== undefined) {
          item.value = this.selectedNode[key];
        } else {
          item.value = item.default;
        }
      }

      const codeRule = this.selectedNode.code_rule;
      this.dialogConfig.fields.customize.value = !!codeRule;
      if (codeRule) {
        for (const [key, value] of Object.entries(codeRule)) {
          this.dialogConfig.fields[key].value = value;
        }
      }

      this.resetRuleCfg();

      this.$refs.dialogForm.show().then(formData => {
        if (formData) {
          if (formData.customize) {
            const code_rule = {};
            for (const [key, item] of Object.entries(this.dialogConfig.fields)) {
              if (item.group === 'code_rule') {
                code_rule[key] = formData[key];
              }
            }
            formData.code_rule = code_rule;
          } else {
            formData.code_rule = null;
          }
          const id = formData.id;
          delete formData.id;

          this.$axios.post('/c2/tenant/material/catalogUpdate', { id, formData }).then(({ data }) => {
            if (data.result === 'fail') {
              this.$q.notify({
                message: data.message || '保存失败',
                color: 'negative',
                icon: 'error',
                position: 'top',
                timeout: 2000
              });
            } else {
              this.$q.notify({
                message: '保存成功',
                color: 'secondary',
                icon: 'done',
                position: 'top',
                timeout: 2000
              });
              this.refresh();
            }
          });
        }
      });
    },
    destroy () {
      this.confirmBox('删除', '确定删除该分类吗？').then(confirm => {
        if (confirm) {
          this.$axios.post('/c2/tenant/material/catalogDestroy', { id: this.selectedId }).then(({ data }) => {
            if (data.result === 'fail') {
              this.$q.notify({
                message: data.message || '删除失败',
                color: 'negative',
                icon: 'error',
                position: 'top',
                timeout: 2000
              });
            } else {
              this.$q.notify({
                message: '删除成功',
                color: 'secondary',
                icon: 'done',
                position: 'top',
                timeout: 2000
              });
              this.refresh();
            }
          });
        }
      });
    },
    resetFilter () {
      this.filter = '';
      this.$refs.filter.focus();
    },
    resetRuleCfg () {
      if (!this.dialogConfig.fields.customize.value) {
        this.dialogConfig.fields.customize.hint = '';
      } else {
        if (this.dialogConfig.fields.prefix_type.value === 'fixed') {
          this.dialogConfig.fields.prefix.type = 'input';
          this.dialogConfig.fields.rule.type = 'checkbox';

          this.dialogConfig.fields.customize.hint = '本级分类及下级未有自定义编码规则的分类，货物编码规则：编码前缀+分类编码+流水号';
        } else {
          this.dialogConfig.fields.prefix.type = '';
          this.dialogConfig.fields.rule.type = '';

          this.dialogConfig.fields.customize.hint = '本级分类及下级未有自定义编码规则的分类，货物编码规则：货物名称的拼音首字母+流水号';
        }
      }
    },
    getNode (id) { // 给父组件调用
      return this.$refs.catalog.getNodeByKey(id);
    },
    // 调整顺序
    // node 树节点
    // flag f - 上移 b - 下移
    changeSort (node, flag) {
      function swapItems (arr, index1, index2) {
        arr[index1] = arr.splice(index2, 1, arr[index1])[0];
        return arr;
      };

      // 上移
      function upRecord (arr, index) {
        if (index == 0) {
          return;
        }
        swapItems(arr, index, index - 1);
      };

      // 下移
      function downRecord (arr, index) {
        if (index == arr.length - 1) {
          return;
        }
        swapItems(arr, index, index + 1);
      };

      // 找到父节点
      const rows = this.$refs.catalog.getNodeByKey(node.parent_id).children;
      const idx = rows.findIndex(v => v.id == node.id);

      if (flag === 'f') {
        upRecord(rows, idx)
      } else {
        downRecord(rows, idx);
      }
      rows.forEach((row, index) => {
        // 排序提交数据库
        this.$axios.post('/c2/tenant/material/catalogUpdate', { id: row.id, formData: { sort: index + 1 } }).then(({ data }) => {
          // this.refresh();
        });
      });
    },
    sortBtnColor (level) {
      if (level == 2) {
        return 'primary';
      } else if (level == 3) {
        return 'accent';
      } else if (level == 4) {
        return 'positive';
      } else {
        return 'orange';
      }
    }
  },
  computed: {
    ...mapState(useStore, ['rights', 'searchParam']),
    canAdd () {
      // 没权限、没选中及第四级不能新增
      return this.rights.material && this.rights.material.add && this.selectedId !== null && (!this.selectedNode || this.selectedNode.levels < 5);
    },
    canEdit () {
      // 没权限及没选中不能修改
      return this.rights.material && this.rights.material.edit && this.selectedId !== null && this.selectedId > 0;
    },
    canDelete () {
      if (this.rights.material && this.rights.material.edit && this.selectedNode) {
        return (!this.selectedNode.children || this.selectedNode.children.length == 0) && this.selectedNode.parent_id > 0;
      } else {
        return false;
      }
    }
  },
  watch: {
    selectedId (val) {
      if (val !== null) {
        this.selectedNode = this.$refs.catalog.getNodeByKey(val);
      } else {
        this.selectedNode = null;
      }
      this.$emit('selected', this.selectedNode);
    },

    'dialogConfig.fields.customize.value' (val) {
      for (const [key, item] of Object.entries(this.dialogConfig.fields)) {
        if (item.group === 'code_rule') {
          item.hidden = !val;
        }
      }
      this.resetRuleCfg();
    },

    'dialogConfig.fields.prefix_type.value' (val) {
      this.resetRuleCfg();
    }
  }
});
</script>
<style lang="scss">
.q-tree__node--selected {
  background-color: $grey-4;
}
</style>
